package com.cwits.wifi.tool;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;


import com.cwits.wifi.util.Dbug;

import org.apache.http.conn.util.InetAddressUtils;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by ZhangHua on 16-03-01.
 */
public class WifiHelper {
    private final String tag = getClass().getSimpleName();
    private static WifiHelper instance = null;
    private WifiManager mWifiManager;
    private List<WifiConfiguration> wifiConfigurationList;
    private List<ScanResult> scanResultList;
    private WifiManager.WifiLock wifiLock;

    public static WifiHelper getInstance(Context context) {
        if (instance == null) {
            instance = new WifiHelper(context);
        }
        return instance;
    }

    private WifiHelper(Context c) {
        if (c != null) {
            mWifiManager = (WifiManager) c.getSystemService(Context.WIFI_SERVICE);
            this.startScan();
        }
    }

    public static boolean isNetworkAvailable(Context context) {
        if (context == null) {
            throw new NullPointerException("context can't be null!");
        }

        ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null) {
                for (NetworkInfo anInfo : info) {
                    if (anInfo.getState() == NetworkInfo.State.CONNECTED) {
                        if (anInfo != null && anInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
                            return false;
                        }
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public static String interceptChar0Before(String s) {
        if (s == null) {
            return null;
        }
        char[] chars = s.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char c : chars) {
            Character ch = c;
            if (0 == ch.hashCode()) {
                break;
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public boolean isWiFiActive(Context context) {
        mWifiManager = (WifiManager) context
                .getSystemService(Context.WIFI_SERVICE);
        return mWifiManager.isWifiEnabled();
    }

    public static boolean isWifi(Context context) {
        if (!isNetworkAvailable(context)) {
            return false;
        }

        ConnectivityManager manager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        String type = networkInfo.getTypeName();

        return (type.equalsIgnoreCase("WIFI"));
    }

    /**
     * 查看WIFI当前是否处于打开状态
     *
     * @return true 处于打开状态；false 处于非打开状态(包括UnKnow状态)。
     */
    public boolean isWifiClosed() {
        int wifiState = getWifiState();
        return wifiState == WifiManager.WIFI_STATE_DISABLED
                || wifiState == WifiManager.WIFI_STATE_DISABLING;
    }

    /**
     * 查看WIFI当前是否处于关闭状态
     *
     * @return true 处于关闭状态；false 处于非关闭状态(包括UNKNOWN状态)
     */
    public boolean isWifiOpened() {
        int wifiState = getWifiState();
        return wifiState == WifiManager.WIFI_STATE_ENABLED
                || wifiState == WifiManager.WIFI_STATE_ENABLING;
    }

    /**
     * 如果WIFI当前处于关闭状态，则打开WIFI
     */
    public void openWifi() {
        if (mWifiManager != null && isWifiClosed()) {
            mWifiManager.setWifiEnabled(true);
        }
    }

    /**
     * 如果WIFI当前处于打开状态，则关闭WIFI
     */
    public void closeWifi() {
        if (mWifiManager != null && isWifiOpened()) {
            mWifiManager.setWifiEnabled(false);
        }
    }

    /**
     * 获取当前Wifi的状态编码
     *
     * @return WifiManager.WIFI_STATE_ENABLED，WifiManager.WIFI_STATE_ENABLING，
     * WifiManager.WIFI_STATE_DISABLED，WifiManager.WIFI_STATE_DISABLING，
     * WifiManager.WIFI_STATE_UnKnow 中间的一个
     */
    public int getWifiState() {
        if (mWifiManager != null) {
            return mWifiManager.getWifiState();
        }
        return 0;
    }

    /**
     * 获取已经配置好的Wifi网络
     *
     * @return
     */
    public List<WifiConfiguration> getSavedWifiConfiguration() {
        return wifiConfigurationList;
    }

    /**
     * 获取扫描到的网络的信息
     *
     * @return
     */
    public List<ScanResult> getWifiScanResult() {
        return scanResultList;
    }

    /**
     * 执行一次Wifi的扫描
     */
    public synchronized void startScan() {
        if (mWifiManager != null) {
            mWifiManager.startScan();
            scanResultList = mWifiManager.getScanResults();
            wifiConfigurationList = mWifiManager.getConfiguredNetworks();
        }
    }

    /**
     * 通过netWorkId来连接一个已经保存好的Wifi网络
     *
     * @param netWorkId
     */
    public void connectionConfiguration(int netWorkId) {
        if (configurationNetWorkIdCheck(netWorkId) && mWifiManager != null) {
            mWifiManager.enableNetwork(netWorkId, true);
        }
    }

    /**
     * 断开一个指定ID的网络
     */
    public void disconnectionConfiguration(int netWorkId) {
        mWifiManager.disableNetwork(netWorkId);
        mWifiManager.disconnect();
    }

    /**
     * 检测尝试连接某个网络时，查看该网络是否已经在保存的队列中间
     *
     * @param netWorkId
     * @return
     */
    private boolean configurationNetWorkIdCheck(int netWorkId) {
        if(null == wifiConfigurationList || wifiConfigurationList.size() == 0){
            return false;
        }
        for (WifiConfiguration temp : wifiConfigurationList) {
            if (temp.networkId == netWorkId) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取Wifi的数据
     *
     * @return
     */
    public WifiInfo getWifiConnectionInfo() {
        return mWifiManager.getConnectionInfo();
    }

    /**
     * 锁定WIFI，使得在熄屏状态下，仍然可以使用WIFI
     */
    public void acquireWifiLock() {
        if (wifiLock != null) {
            wifiLock.acquire();
        }
    }

    /**
     * 解锁WIFI
     */
    public void releaseWifiLock() {
        if (wifiLock != null) {
            if (wifiLock.isHeld()) {
                wifiLock.acquire();
            }
        }
    }

    /**
     * 创建一个WifiLock
     */
    public void createWifiLock() {
        if (mWifiManager != null) {
            wifiLock = mWifiManager.createWifiLock("wifiLock");
        }
    }

    /**
     * 保存一个新的网络
     *
     * @param _wifiConfiguration
     */
    public int addNetWork(WifiConfiguration _wifiConfiguration) {
        int netWorkId = -255;
        if (_wifiConfiguration != null && mWifiManager != null) {
            netWorkId = mWifiManager.addNetwork(_wifiConfiguration);
            startScan();
        }
        return netWorkId;
    }

    /**
     * 保存并连接到一个新的网络
     *
     * @param _wifiConfiguration
     */
    public void addNetWorkAndConnect(WifiConfiguration _wifiConfiguration) {
        int netWorkId = addNetWork(_wifiConfiguration);
        if (netWorkId != -255) {
            connectionConfiguration(netWorkId);
        }
    }

    /**
     * 获取当前连接状态中的Wifi的信号强度
     *
     * @return
     */
    public int getConnectedWifiLevel() {
        WifiInfo wifiInfo = getWifiConnectionInfo();
        if (wifiInfo != null) {
            String connectedWifiSSID = wifiInfo.getSSID();
            if (scanResultList != null) {
                for (ScanResult temp : scanResultList) {
                    if (temp.SSID.replace("\"", "").equals(
                            connectedWifiSSID.replace("\"", ""))) {
                        return temp.level;
                    }
                }
            }
        }
        return 1;
    }

    /**
     * 删除一个已经保存的网络
     *
     * @param netWorkId
     */
    public void remoteNetWork(int netWorkId) {
        if (mWifiManager != null) {
            mWifiManager.removeNetwork(netWorkId);
        }
    }

    /**
     * Wifi加密类型的描述类
     */
    public enum WifiCipherType {
        NONE, IEEE8021XEAP, WEP, WPA, WPA2, WPAWPA2
    }

    /**
     * 连接一个WIFI
     *
     * @param ssid
     * @param password
     * @param wifiCipherType
     */
    public void addNetWorkAndConnect(String ssid, String password, WifiCipherType wifiCipherType) {
        if (mWifiManager != null && wifiCipherType != null) {
            WifiConfiguration wifiConfig = createWifiConfiguration(ssid, password, wifiCipherType);
            WifiConfiguration temp = isWifiConfigurationSaved(wifiConfig);
            if (temp != null) {
                if(mWifiManager.removeNetwork(temp.networkId)){
                    addNetWorkAndConnect(wifiConfig);
                }else{
                    connectionConfiguration(temp.networkId);
                }
            }else {
                addNetWorkAndConnect(wifiConfig);
            }
            Dbug.d(tag, "getWifiState:" + mWifiManager.getWifiState());

        }
    }

    private WifiConfiguration isWifiConfigurationSaved(
            WifiConfiguration wifiConfig) {

        if (wifiConfigurationList == null) {
            this.startScan();
        }
        wifiConfigurationList = mWifiManager
                .getConfiguredNetworks();
        for (WifiConfiguration temp : wifiConfigurationList) {
            if (temp.SSID.equals(wifiConfig.SSID)) {
                return temp;
            }
        }
        return null;
    }

    private WifiConfiguration createWifiConfiguration(String ssid, String password, WifiCipherType type) {
        WifiConfiguration newWifiConfiguration = new WifiConfiguration();
        newWifiConfiguration.allowedAuthAlgorithms.clear();
        newWifiConfiguration.allowedGroupCiphers.clear();
        newWifiConfiguration.allowedKeyManagement.clear();
        newWifiConfiguration.allowedPairwiseCiphers.clear();
        newWifiConfiguration.allowedProtocols.clear();
        newWifiConfiguration.SSID = "\"" + ssid + "\"";
        switch (type) {
            case NONE:
                newWifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
                break;
            case IEEE8021XEAP:
                break;
            case WEP:
                break;
            case WPA:
                newWifiConfiguration.preSharedKey = "\"" + password + "\"";
                newWifiConfiguration.hiddenSSID = true;
                newWifiConfiguration.allowedAuthAlgorithms
                        .set(WifiConfiguration.AuthAlgorithm.OPEN);
                newWifiConfiguration.allowedGroupCiphers
                        .set(WifiConfiguration.GroupCipher.TKIP);
                newWifiConfiguration.allowedKeyManagement
                        .set(WifiConfiguration.KeyMgmt.WPA_PSK);
                newWifiConfiguration.allowedPairwiseCiphers
                        .set(WifiConfiguration.PairwiseCipher.TKIP);
                // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
                newWifiConfiguration.allowedGroupCiphers
                        .set(WifiConfiguration.GroupCipher.CCMP);
                newWifiConfiguration.allowedPairwiseCiphers
                        .set(WifiConfiguration.PairwiseCipher.CCMP);
                newWifiConfiguration.status = WifiConfiguration.Status.ENABLED;

                break;
            case WPA2:
                newWifiConfiguration.preSharedKey = "\"" + password + "\"";
                newWifiConfiguration.allowedAuthAlgorithms
                        .set(WifiConfiguration.AuthAlgorithm.OPEN);
                newWifiConfiguration.allowedGroupCiphers
                        .set(WifiConfiguration.GroupCipher.TKIP);
                newWifiConfiguration.allowedGroupCiphers
                        .set(WifiConfiguration.GroupCipher.CCMP);
                newWifiConfiguration.allowedKeyManagement
                        .set(WifiConfiguration.KeyMgmt.WPA_PSK);
                newWifiConfiguration.allowedPairwiseCiphers
                        .set(WifiConfiguration.PairwiseCipher.TKIP);
                newWifiConfiguration.allowedPairwiseCiphers
                        .set(WifiConfiguration.PairwiseCipher.CCMP);
                newWifiConfiguration.allowedProtocols
                        .set(WifiConfiguration.Protocol.RSN);
                newWifiConfiguration.status = WifiConfiguration.Status.ENABLED;
                break;
            default:
                return null;
        }
        return newWifiConfiguration;
    }

    public static int getNetWorkType(Context context) {
        if (!isNetworkAvailable(context)) {
            return 0;
        }

        ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
        String type = networkInfo.getTypeName();

        if (type.equalsIgnoreCase("WIFI")) {
            return 1;
        } else if (type.equalsIgnoreCase("MOBILE")) {
            TelephonyManager telephonyManager = (TelephonyManager) context
                    .getSystemService(Context.TELEPHONY_SERVICE);
            switch (telephonyManager.getNetworkType()) {
                case TelephonyManager.NETWORK_TYPE_EVDO_0:// ~ 400-1000 kbps
                case TelephonyManager.NETWORK_TYPE_EVDO_A:// ~ 600-1400 kbps
                case TelephonyManager.NETWORK_TYPE_HSDPA:// ~ 2-14 Mbps
                case TelephonyManager.NETWORK_TYPE_HSPA:// ~ 700-1700 kbps
                case TelephonyManager.NETWORK_TYPE_HSUPA:// ~ 1-23 Mbps
                case TelephonyManager.NETWORK_TYPE_UMTS: // ~ 400-7000 kbps
                case TelephonyManager.NETWORK_TYPE_EVDO_B:// ~ 5 Mbps
                    return 1;
                case TelephonyManager.NETWORK_TYPE_1xRTT:// ~ 50-100 kbps
                case TelephonyManager.NETWORK_TYPE_CDMA:// ~ 14-64 kbps
                case TelephonyManager.NETWORK_TYPE_EDGE:// ~ 50-100 kbps
                case TelephonyManager.NETWORK_TYPE_GPRS:// ~ 100 kbps
                case TelephonyManager.NETWORK_TYPE_IDEN:// ~25 kbps
                case TelephonyManager.NETWORK_TYPE_UNKNOWN:
                default:
                    return 0;
            }
        }

        return 0;
    }

    /**
     * 枚举网络状态
     * NET_NO：没有网络
     * NET_2G:2g网络
     * NET_3G：3g网络
     * NET_4G：4g网络
     * NET_WIFI：wifi
     * NET_UNKNOWN：未知网络
     */
    public enum NetState {
        NET_NO, NET_2G, NET_3G, NET_4G, NET_WIFI, NET_UNKNOWN
    }

    /**
     * 判断当前网络连接类型
     *
     * @param context
     * @return 状态码
     */
    public static NetState getConnectedType(Context context) {
        NetState stateCode = NetState.NET_NO;
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo ni = cm.getActiveNetworkInfo();
        if (ni != null && ni.isConnectedOrConnecting()) {
            switch (ni.getType()) {
                case ConnectivityManager.TYPE_WIFI:
                    stateCode = NetState.NET_WIFI;
                    break;
                case ConnectivityManager.TYPE_MOBILE:
                    switch (ni.getSubtype()) {
                        case TelephonyManager.NETWORK_TYPE_GPRS: //联通2g
                        case TelephonyManager.NETWORK_TYPE_CDMA: //电信2g
                        case TelephonyManager.NETWORK_TYPE_EDGE: //移动2g
                        case TelephonyManager.NETWORK_TYPE_1xRTT:
                        case TelephonyManager.NETWORK_TYPE_IDEN: //api<8 : replace by 11
                            stateCode = NetState.NET_2G;
                            break;
                        case TelephonyManager.NETWORK_TYPE_EVDO_A: //电信3g
                        case TelephonyManager.NETWORK_TYPE_UMTS:
                        case TelephonyManager.NETWORK_TYPE_EVDO_0:
                        case TelephonyManager.NETWORK_TYPE_HSDPA:
                        case TelephonyManager.NETWORK_TYPE_HSUPA:
                        case TelephonyManager.NETWORK_TYPE_HSPA:
                        case TelephonyManager.NETWORK_TYPE_EVDO_B: //api<9 : replace by 14
                        case TelephonyManager.NETWORK_TYPE_EHRPD:  //api<11 : replace by 12
                        case TelephonyManager.NETWORK_TYPE_HSPAP:  //api<13 : replace by 15
                            stateCode = NetState.NET_3G;
                            break;
                        case TelephonyManager.NETWORK_TYPE_LTE:   //api<11 : replace by 13
                            stateCode = NetState.NET_4G;
                            break;
                        default:
                            // http://baike.baidu.com/item/TD-SCDMA 中国移动 联通 电信 三种3G制式
                            if (ni.getSubtypeName().equalsIgnoreCase("TD-SCDMA") ||
                                    ni.getSubtypeName().equalsIgnoreCase("WCDMA") ||
                                    ni.getSubtypeName().equalsIgnoreCase("CDMA2000")) {
                                stateCode = NetState.NET_3G;
                            }else{
                                stateCode = NetState.NET_UNKNOWN;
                            }

                    }
                    break;
                default:
                    stateCode = NetState.NET_UNKNOWN;
            }

        }
        return stateCode;
    }

    public static String getWIFIIP(Context context) {
        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiinfo = wifiManager.getConnectionInfo();
        String ip = formatIpAddress(wifiinfo.getIpAddress());
        if (ip.equals("0.0.0.0")) {
            ip = getLocalIpAddress();
            if (ip.equals("0.0.0.0")) {
                Log.e("WIFP_IP", "WIFI IP Error");
            }
        }
        return ip;
    }

    private static String getLocalIpAddress() {
        try {
            String ipv4;
            List<NetworkInterface> nilist = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface ni : nilist) {
                List<InetAddress> ialist = Collections.list(ni.getInetAddresses());
                for (InetAddress address : ialist) {
                    ipv4 = address.getHostAddress();
                    if (!address.isLoopbackAddress() && InetAddressUtils.isIPv4Address(ipv4)) {
                        return ipv4;
                    }
                }
            }
        } catch (SocketException ex) {
            ex.printStackTrace();
        }
        return "0.0.0.0";
    }

    private static String formatIpAddress(int ipAddress) {
        return (ipAddress & 0xFF) + "." +
                ((ipAddress >> 8) & 0xFF) + "." +
                ((ipAddress >> 16) & 0xFF) + "." +
                (ipAddress >> 24 & 0xFF);
    }


    /**
     * WIFI 是否打开
     *
     * @return
     */
    public boolean isWifiOpen() {
        return mWifiManager.isWifiEnabled();
    }

    public List<ScanResult> getSpecifiedSSIDList(final String specified) {
        List<ScanResult> list = new ArrayList();
        String[] s = specified.split(",");
        //int index = specified.lastIndexOf(",");
        //String str1 = specified.substring(0, index);
        //String str2 = specified.substring(index + 1,specified.length());
        if (mWifiManager != null) {
            mWifiManager.startScan();
            List<ScanResult> scanResultList = mWifiManager.getScanResults();
            if (scanResultList == null){
                Dbug.e(tag, "scanResultList is null");
                return null;
            }
            boolean flag = false;
            for (ScanResult scanResult : scanResultList) {
//                Dbug.d(tag, "scanResult.SSID=" + scanResult.SSID+ ", capabilities:" + scanResult.capabilities);
                flag = false;
                for(int i = 0;i < s.length;i++){
                    if(scanResult.SSID.startsWith(s[i])){
                        flag = true;
                        break;
                    }else{
                        continue;
                    }
                }
                if (flag||scanResult.SSID.contains("168")||scanResult.SSID.contains("chainway_")) {
                    list.add(scanResult);
                }
            }
        }
        return list;
    }

    public void connectOtherWifi(String exceptSpecified){
        if(getWifiConnectionInfo() == null || TextUtils.isEmpty(getWifiConnectionInfo().getSSID())){
            Dbug.e(tag, "WifiInfo or SSID is null");
            return;
        }
        String[] s = exceptSpecified.split(",");
        //int index = exceptSpecified.lastIndexOf(",");
        //String str1 = exceptSpecified.substring(0, index);
        //String str2 = exceptSpecified.substring(index + 1,exceptSpecified.length());
        List<WifiConfiguration> saveWifiList = getSavedWifiConfiguration();
        List<ScanResult> scanResultList = getWifiScanResult();
        if(scanResultList == null){
            return;
        }
        String networkName;
        boolean flag = false;
        for (ScanResult scanResult : scanResultList){

            flag = false;
            for(int i = 0;i < s.length;i++){
                if(scanResult.SSID.startsWith(s[i])){
                    flag = true;
                    break;
                }else{
                    continue;
                }
            }
            if (flag||scanResult.SSID.contains("168")||scanResult.SSID.contains("chainway_")){
                continue;
            }
//            Dbug.e(tag,"scanResult.SSID-> " + scanResult.SSID);

            for(WifiConfiguration config : saveWifiList){
                networkName = config.SSID.replace("\"", "");
                if(scanResult.SSID.equals(networkName)){
//                    Dbug.e(tag, "Save networkName-> " + config.SSID + " network_id -> " + config.networkId);
                    connectionConfiguration(config.networkId);
                    return;
                }
            }
        }
    }

    public void connectWifi(String ssid, String password) {

        WifiConfiguration conf = new WifiConfiguration();
        conf.SSID = "\"" + ssid + "\"";   // Please note the quotes. String should contain ssid in quotes
        conf.preSharedKey = "\"" + password + "\"";
        int netId = mWifiManager.addNetwork(conf);
        Dbug.d(tag, "net id ==:" + netId);

        List<WifiConfiguration> list = mWifiManager.getConfiguredNetworks();
        for (WifiConfiguration i : list) {
            if (i.SSID != null && i.SSID.equals("\"" + ssid + "\"")) {
                Dbug.i(tag, "net id ==:" + i.networkId);
                mWifiManager.disconnect();
                mWifiManager.enableNetwork(i.networkId, true);
                mWifiManager.reconnect();
                break;
            }
        }
    }
}
